#ifndef __TABLE_PROTO_H__
#define __TABLE_PROTO_H__

#include "layout.h"
#include "bmap.h"
#include "chunk.h"

#define TABLE_PROTO_INFO_ATTR 0
#define TABLE_PROTO_BNO_EXT   1
#define TABLE_PROTO_INFO_VFM  2

typedef enum {
        SNAP_ALL = 0,
        SNAP_SYSTEM = 1,
        SNAP_USER = 2,
} snap_type_t;

#if 0
/* echo -n '__MAGIC_INFO__' | md5sum */
#define MAGIC_MD5SUM         "060c0b48fc85115beb76ee09623e0da7"
#define MAGIC_SIZE  32
#endif

static inline void table_proto_layout_check(int item_size, int item_count)
{
        //YASSERT((TABLE_PROTO_MAP_AREA + TABLE_PROTO_INFO_AREA) % PAGE_SIZE == 0);

        YASSERT((TABLE_PROTO_MAP_AREA + TABLE_PROTO_INFO_AREA)
                + (item_count * item_size) <= (int)LICH_CHUNK_SPLIT);

        YASSERT(item_count / CHAR_BIT < TABLE_PROTO_MAP_AREA);
}

typedef struct {
        struct list_head hook;
        char *key;
        chkinfo_t *chkinfo;
        chkstat_t *chkstat;
        uint64_t snap_version;
        uint64_t snap_from;
        uint32_t loc;
        char unlink;
        char buf[0];
} snap_t;

typedef struct __table_proto {
        struct list_head hook;

        int (*update)(struct __table_proto *, uint32_t loc, const void *value, int len);

        int (*insert)(struct __table_proto *, uint32_t loc, const void *value, int len);
        int (*del)(struct __table_proto *, uint32_t loc);
        int (*batch_del)(struct __table_proto *, uint32_t *loc, uint32_t n_loc);
        
        int (*setinfo)(struct __table_proto *, const void *value, int len, int info_type);
        int (*getinfo)(struct __table_proto *, void *value, int *len, int info_type);

        int (*iterator)(struct __table_proto *, int (*iterator)(const void *, int, int, void *), int idx, void *context);
        int (*load)(struct __table_proto *);

        int (*get_empty)(struct __table_proto *, uint32_t *loc);

        uint32_t item_size;
        uint32_t item_count;
        bmap_t bmap;
        chkid_t chkid;

        struct table_snapshot {
                int (*create)(struct __table_proto *, const char *key, const chkinfo_t *chkinfo,
                                uint64_t snap_version, uint64_t snap_from);
                int (*remove)(struct __table_proto *, const char *key);
                int (*get_version)(struct __table_proto *, const chkid_t *chkid,
                                uint64_t *snap_version);
                int (*get_byname)(struct __table_proto *, const char *key, chkinfo_t *chkinfo,
                                uint64_t *snap_version);
                int (*get_byversion)(struct __table_proto *, uint64_t snap_version,
                                chkinfo_t *chkinfo, char *name);
                int (*rename)(struct __table_proto *, const char *from, const char *to);
                int (*list)(struct __table_proto *, const char *pool, uint64_t offset, void *_buf,
                                 int *_buflen);
                int (*unintact)(struct __table_proto *, func3_t func3, void *_arg);
                int (*iterator)(struct __table_proto *, func2_t func2, void *_arg);
                int (*iterator2)(struct __table_proto *, func_int2_t func2, void *_arg);
                int (*last)(struct __table_proto *, nid_t *snapnid, fileid_t *fileid, char *name, uint64_t *snap_version);
                int (*next)(struct __table_proto *, const fileid_t *from, fileid_t *fileid, char *name, uint64_t *snap_version);
                int (*prev)(struct __table_proto *, const fileid_t *from, fileid_t *fileid, char *name, uint64_t *snap_version);

                int (*getinfo)(struct __table_proto *, const fileid_t *fileid, chkinfo_t *chkinfo);
                int (*setinfo)(struct __table_proto *, const fileid_t *fileid, const chkinfo_t *chkinfo, uint64_t info_version);
                int (*is_empty)(struct __table_proto *, int *empty);
                int (*is_deleting)(struct __table_proto *, int *deleting);
                int (*count)(struct __table_proto *, int snap_type, int *count);

                int (*updateparent)(struct __table_proto *, const char *name, const uint64_t snap_from);
                int (*last_version)(struct __table_proto *, uint64_t *snap_version);
                int (*usable_version)(struct __table_proto *, uint64_t *snap_version);
                int (*has_child)(struct __table_proto *, uint64_t snap_version);
                int (*list_child)(struct __table_proto *, uint64_t snap_from, struct list_head *list);
                int (*list_parent)(struct __table_proto *, uint64_t snap_version, struct list_head *list);
                int (*list_descendant)(struct __table_proto *, uint64_t snap_version, struct list_head *list);

                bmap_t bmap; //snapshot bitmap
                struct list_head snap;
        } *snap;

        struct table_xattr {
                int (*set)(struct __table_proto *, const char *key, const char *value, int flag);
                int (*get)(struct __table_proto *, const char *key, char *value);
                int (*remove)(struct __table_proto *, const char *key);
                int (*list)(struct __table_proto *, char *buf);

                bmap_t bmap; //xattr bitmap
                hashtable_t tab;
        } *xattr;

        //table_snapshot_t *snapshot;
        //table_xattr_t *xattr;

        int map_loaded; // 0: unload 1:load
        int item_loaded;
        int _xattr;
        int _snap;

        chkinfo_t *chkinfo;
        chkstat_t *chkstat;
        char __chkinfo__[CHKINFO_MAX];
        char __chkstat__[CHKSTAT_MAX];
} table_proto_t;

int table_proto_load(table_proto_t **_table_proto, const chkinfo_t *chkinfo,
                     const chkstat_t *chkstat, int item_size, int item_count, int xattr, int snap);
int table_proto_init(table_proto_t **_table_proto, const chkinfo_t *chkinfo,
                     const chkstat_t *chkstat, int item_size, int item_count, int xattr, int snap);
void table_proto_destroy(table_proto_t *table_proto);
int table_proto_create(const char *pool, const chkinfo_t *chkinfo, const fileid_t *parent,
                       const nid_t *parentnid, int initzero, const void *info, int size, char *data, int data_size);

int __table_proto_write(const chkinfo_t *chkinfo, chkstat_t *chkstat, const char *buf,
                        int size, int offset);
int table_proto_write(const chkinfo_t *chkinfo, chkstat_t *chkstat, const buffer_t *buf,
                        int size, int offset);
int __table_proto_read(const chkinfo_t *chkinfo, const chkstat_t *chkstat, char *buf,
                       int size, int offset, int *_size);
int table_proto_read(const chkinfo_t *chkinfo, const chkstat_t *chkstat, buffer_t *buf,
                       int size, int offset, int *_size);

int table_xattr_init(table_proto_t *table_proto);
void table_xattr_destroy(table_proto_t *table_proto);

int table_snap_init(table_proto_t *table_proto);
void table_snap_destroy(table_proto_t *table_proto);

#endif
